//
//  JWTree.m
//  KotH
//
//  Created by James Weatherley on 16/08/2008.
//  Copyright 2008 James Weatherley. All rights reserved.
//

#import "JWTree.h"
#import "../koth.h"
#import "../geometry/geometry.h"


@implementation JWTree

@synthesize selected;
@synthesize square;

#pragma mark Protocol
-(id)initWithSquare:(JWSquare*)square_
{
	self = [super init];
	
	square = square_;
	square.tree = self;
	selected = NO;
	[self calculateTreeGeometry];
	
	return self;
}

-(NSObject<JWManager>*)manager
{
	return [[JWManagers sharedManager] managerOfClass:[JWTreeManager class]];
}

+(NSInteger)energy
{
	return 1;
}

#pragma mark Geometry
-(void)calculateTreeGeometry
{
	GLfloat radius = 0.75f;
	GLfloat theta = 0.0f;
	
	float x;
	float z;
	
	// Tree leaves.
	for(NSUInteger i = 0; i < 3; ++i) {
		x = radius * sin(theta);
		z = radius * cos(theta);
		treeVertices[i][0] = [square x] + 0.5f + x;
		treeVertices[i][1] = [square height] + [[square boxes] count] + 0.5f;
		treeVertices[i][2] = [square z] + 0.5f + z;
		theta += 2 * M_PI / 3;
	}
	treeVertices[3][0] = [square x] + 0.5f;
	treeVertices[3][1] = [square height] + [[square boxes] count] + 0.5f + 2.0f;
	treeVertices[3][2] = [square z] + 0.5f;
	
	// Tree trunk.
	theta = 0.0f;
	radius = 0.25f;
	for(NSUInteger i = 0; i < 4; ++i) {
		x = radius * sin(theta);
		z = radius * cos(theta);
		trunkVertices[i][0] = [square x] + 0.5f + x;
		trunkVertices[i][1] = [square height] + [[square boxes] count];
		trunkVertices[i][2] = [square z] + 0.5f + z;
		trunkVertices[i + 4][0] = [square x] + 0.5f + x;
		trunkVertices[i + 4][1] = [square height] + [[square boxes] count] + 0.5f;
		trunkVertices[i + 4][2] = [square z] + 0.5f + z;
		theta += M_PI / 2;
	}
	
	// Leaf normals.
	calculateNormal(treeVertices[1], treeVertices[2], treeVertices[3], treeNormals[0]);
	calculateNormal(treeVertices[0], treeVertices[3], treeVertices[2], treeNormals[1]);
	calculateNormal(treeVertices[3], treeVertices[0], treeVertices[1], treeNormals[2]);
	calculateNormal(treeVertices[0], treeVertices[2], treeVertices[1], treeNormals[3]);
	
	// Trunk normals.
	calculateNormal(trunkVertices[0], trunkVertices[1], trunkVertices[4], trunkNormals[0]);
	calculateNormal(trunkVertices[1], trunkVertices[2], trunkVertices[5], trunkNormals[1]);
	calculateNormal(trunkVertices[2], trunkVertices[3], trunkVertices[6], trunkNormals[2]);
	calculateNormal(trunkVertices[3], trunkVertices[0], trunkVertices[7], trunkNormals[3]);
	
	// Faces.
	vectorCopy(treeVertices[1], treeFaces[0][0]);
	vectorCopy(treeVertices[2], treeFaces[0][1]);
	vectorCopy(treeVertices[3], treeFaces[0][2]);
	
	vectorCopy(treeVertices[0], treeFaces[1][0]);
	vectorCopy(treeVertices[3], treeFaces[1][1]);
	vectorCopy(treeVertices[2], treeFaces[1][2]);
	
	vectorCopy(treeVertices[3], treeFaces[2][0]);
	vectorCopy(treeVertices[0], treeFaces[2][1]);
	vectorCopy(treeVertices[1], treeFaces[2][2]);
	
	vectorCopy(treeVertices[0], treeFaces[3][0]);
	vectorCopy(treeVertices[2], treeFaces[3][1]);
	vectorCopy(treeVertices[1], treeFaces[3][2]);
}

/*
-(void)getTreeGeometryVertices:(vec3_t[])vertices normals:(vec3_t[])normals count:(NSUInteger)count
{
	assert(count == 4);
	for(NSUInteger i = 0; i < count; ++i) {
		vectorCopy(treeVertices[i], vertices[i]);
		vectorCopy(treeNormals[i], normals[i]);
	}
}
*/

-(vec3_t*)treeNormals
{
	return treeNormals;
}

-(vec3_t*)treeVertices
{
	return treeVertices;
}

-(vec3_t*)trunkNormals
{
	return trunkNormals;
}

-(vec3_t*)trunkVertices
{
	return trunkVertices;
}

#pragma mark Implementation
-(BOOL)valid
{
	return self == [square tree];
}

#pragma mark Hit Test
-(BOOL)intersectWithRayFrom:(const vec3_t)point direction:(const vec3_t)dir
{
	vec3_t boxMin;
	vec3_t boxMax;
	NSInteger x = square.x;
	NSInteger z = square.z;
	float height = square.height;
	
	boxMin[0] = x + 0.25f;
	boxMin[1] = height;
	boxMin[2] = z + 0.25f;
	
	boxMax[0] = x + 0.75f;
	boxMax[1] = height + 0.5;
	boxMax[2] = z + 0.75f;
	
	BOOL hit = intersectBox(boxMin, boxMax, point, dir);
	
	if(!hit) {
		vec3_t intersect;
		
		for(NSUInteger i = 0; i < 4; ++i) {
			if(intersectPlane(treeFaces[i][0], treeNormals[i], point, dir, intersect)) {
				hit = intersectPolygon(treeFaces[i], 3, intersect, treeNormals[i]);
				if(hit) {
					break;
				}
			}
		}
	}
	return hit;
}

@end
